9021. Количество чисел вида 2^x * 3^y

 

Найдите количество целых чисел на отрезке [ab], представимых в виде 2x * 3y при x ≥ 0, y ≥ 0.

 

Вход. Содержит не более 106 строк. Каждая строка содержит два целых числа a и b (0 ≤ a ≤ b ≤ 1018), задающих один запрос.

 

Выход. Для каждого запроса выведите в отдельной строке количество целых чисел на отрезке [ab] включительно, которые можно представить в виде 2x * 3y.

 

Пример входа

Пример выхода

1 10

100 200

7

5

 

 

РЕШЕНИЕ

бинарный поиск

 

Анализ алгоритма

Чисел вида 2x * 3y, не превышающих 1018, не так уж много. Сгенерируем их и сохраним в массиве v.

Количество искомых чисел f(a, b) на отрезке [ab] можно найти по формуле:

f(0, b) – f(0, a – 1)

Здесь f(0, q) обозначает количество чисел вида 2x * 3y, не превышающих q. Ответ на этот запрос можно найти с помощью бинарного поиска на массиве v.

 

Пример

Сгенерируем все числа вида 2x * 3y, не превышающие 200.

 

Отрезку [1; 10] принадлежит 7 чисел (выделены синим).

Отрезку [100; 200] принадлежит 5 чисел (выделены зеленым).

 

Найдем решение для отрезка [10; 20]:

upper_bound(v.begin(), v.end(), 20) upper_bound(v.begin(), v.end(), 9) = 3

Действительно, отрезку [10; 20] принадлежит 3 числа искомого вида:

12, 16, 18

 

Реализация алгоритма

Объявим константу MAX = 1018 и рабочий массив v.

 

#define MAX 1000000000000000000LL

vector<long long> v;

 

Функция preprocess генерирует все числа вида 2x * 3y, не превышающие 1018, и сохраняет их в массиве v. Для каждого значения x = 1, 2, 4, 8, … перебираем числа y = 1, 3, 9, 27, … до тех пор, пока x * y < MAX.

 

void preprocess()

{

  long long x = 1, y = 1;

  while (x < MAX)

  {

    while (x * y < MAX)

    {

      v.push_back(x * y);

      y *= 3;

    }

    x *= 2;

    y = 1;

  }

 

Отсортируем числа в массиве v.

 

  sort(v.begin(), v.end());

}

 

Основная часть программы. Генерируем массив чисел вида 2x * 3y.

 

preprocess();

 

Читаем запрос – отрезок [ab]. Количество искомых чисел на этом отрезке вычисляется по формуле:

f(a, b) = f(0, b)f(0, a – 1)

 

while (scanf("%lld %lld", &a, &b) == 2)

{

  res = upper_bound(v.begin(), v.end(), b)

        upper_bound(v.begin(), v.end(), a - 1);

  printf("%lld\n", res);

}